#include "tcp_server.h"

// 在线客户端个数
int online_client_num = 0;

// 初始化TCP服务器
P_SBI Tcp_Server_Init(int ser_port)
{
    P_SBI server_inf_struct = (P_SBI)malloc(sizeof(SBI));
    if (server_inf_struct == (P_SBI)NULL)
    {
        perror("malloc ...");
        return (P_SBI)-1;
    }

    memset(server_inf_struct, 0, sizeof(SBI));

    // 创建套接字
    if ((server_inf_struct->ser_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("socket ... ");
        return (P_SBI)-1;
    }

    // 设置TCP服务器主结构体信息
    struct sockaddr_in tcp_ser_inf;
    memset(&tcp_ser_inf, 0, sizeof(tcp_ser_inf));

    tcp_ser_inf.sin_family = AF_INET;
    tcp_ser_inf.sin_port = htons(ser_port);
    tcp_ser_inf.sin_addr.s_addr = htonl(INADDR_ANY);

    // 设置socket为可重用
    int opt = 1;
    if (setsockopt(server_inf_struct->ser_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0)
    {
        perror("setsockopt failed");
    }

    // 绑定
    if (bind(server_inf_struct->ser_fd, (struct sockaddr *)&tcp_ser_inf, sizeof(tcp_ser_inf)) == -1)
    {
        perror("bind ...");
        return (P_SBI)-1;
    }

    // 监听
    if (listen(server_inf_struct->ser_fd, 15) == -1)
    {
        perror("listen ...");
        return (P_SBI)-1;
    }

    // 创建在线客户端链表头节点
    if ((server_inf_struct->online_client_head = Create_Client_Node()) == (P_CN)-1)
    {
        printf("创建在线客户端链表头节点失败！\n");
        return (P_SBI)-1;
    }

    // 初始化互斥锁
    if (pthread_mutex_init(&server_inf_struct->mutex, NULL) != 0)
    {
        perror("pthread_mutex_init ...");
        return (P_SBI)-1;
    }

    // 创建线程等待客户端连接
    if (pthread_create(&server_inf_struct->wait_id, NULL, Wait_For_Client_Connect, (void *)server_inf_struct) != 0)
    {
        perror("pthread_create ...");
        return (P_SBI)-1;
    }

    // 线程池初始化
    server_inf_struct->pthread_pool = Pthread_Pool_Init();
    if (server_inf_struct->pthread_pool == (P_SPI)-1)
    {
        printf("线程池初始化失败！\n");
        return (P_SBI)-1;
    }
    printf("线程池初始化成功！\n");
    return server_inf_struct;
}

// 创建一个客户端结点
P_CN Create_Client_Node()
{
    P_CN client_node = (P_CN)malloc(sizeof(CN));
    if (client_node == (P_CN)NULL)
    {
        perror("malloc ...");
        return (P_CN)-1;
    }

    memset(client_node, 0, sizeof(CN));

    client_node->next = client_node;
    client_node->prev = client_node;

    return client_node;
}

// 创建线程等待客户端连接
void *Wait_For_Client_Connect(void *arg)
{
    P_SBI server_inf_struct = (P_SBI)arg;
    struct sockaddr_in cli_inf; // 存放连接客户端的网络信息结构体
    int addr_len = sizeof(cli_inf);
    while (1)
    {
        memset(&cli_inf, 0, addr_len); // 清空结构体变量

        int cli_fd = accept(server_inf_struct->ser_fd, (struct sockaddr *)&cli_inf, &addr_len);
        if (cli_fd == -1)
        {
            perror("accept ...");
            pthread_exit((void *)-1);
        }

        printf("\n%s来了！ %d\n", inet_ntoa(cli_inf.sin_addr), online_client_num++);

        // 创建新的客户端结点
        P_CN new_client_node = Create_Client_Node();
        if (new_client_node == (P_CN)-1)
        {
            printf("创建客户端结点失败！\n");
            pthread_exit((void *)-1);
        }

        // 把当前连接过来的客户端的 套接字、IP、主结构体 存放到结点中
        new_client_node->cli_fd = cli_fd;
        strcpy(new_client_node->cli_ip, inet_ntoa(cli_inf.sin_addr));
        new_client_node->server_inf_struct = server_inf_struct;

        // 使用线程池添加客户端连接任务
        if (!Add_Task_Node(server_inf_struct->pthread_pool, "客户端连接", new_client_node))
        {
            printf("向线程池添加任务失败！\n");
            close(cli_fd);
            free(new_client_node);
            pthread_exit((void *)-1);
        }
        Wake_Up_Pthread(new_client_node->server_inf_struct->pthread_pool);
    }

    pthread_exit((void *)0);
}

// 尾插法添加结点
bool Add_Client_Node(P_CN client_head, P_CN new_client_node)
{
    if (client_head == (P_CN)NULL || new_client_node == (P_CN)NULL)
    {
        printf("结点异常！\n");
        return false;
    }

    // 变更原尾节点指针域
    new_client_node->prev = client_head->prev;
    client_head->prev->next = new_client_node;

    // 变更头节点指针域
    new_client_node->next = client_head;
    client_head->prev = new_client_node;

    return true;
}

// 群聊信息发送线程任务函数
bool Broadcast_Task(P_CN client_node)
{

    char msg[MSG_MAX_LEN];
    while (1)
    {
        memset(msg, 0, MSG_MAX_LEN);
        int read_ret = read(client_node->cli_fd, msg, MSG_MAX_LEN);
        // 读取客户端发送过来的消息
        if (read_ret == -1)
        {
            perror("read ...");
            return false;
        }
        else if (read_ret == 0)
        {
            printf("%s掉线\n", client_node->cli_ip);

            // 上锁
            pthread_mutex_lock(&(client_node->server_inf_struct->mutex));

            if (Del_Client_Node(client_node) == false)
            {
                printf("删除下线客户端结点失败！\n");
                // 解锁
                pthread_mutex_unlock(&(client_node->server_inf_struct->mutex));

                return false;
            }

            pthread_mutex_unlock(&(client_node->server_inf_struct->mutex));
            // 解锁

            free(client_node); // 释放当前客户端结点堆空间

            break;
        }
        else // 有消息
        {
            // printf("%s发送:%s\n", client_node->cli_ip, msg);

            if (strcmp(msg, EXIT_MASK) == 0)
            {
                printf("%s退出群聊！\n", client_node->cli_ip);

                break;
            }

            if (Send_All_Client(client_node, msg, SEND_MODE_BASE) == false)
            {
                printf("发送广播消息失败！\n");
                return false;
            }
        }
    }

    return true;
}

// 删除结点
bool Del_Client_Node(P_CN client_node)
{
    if (client_node == (P_CN)NULL)
    {
        printf("结点异常！\n");
        return false;
    }
    client_node->prev->next = client_node->next;
    client_node->next->prev = client_node->prev;

    client_node->prev = (P_CN)NULL;
    client_node->next = (P_CN)NULL;

    close(client_node->cli_fd);
    return true;
}

// 将信息广播
bool Send_All_Client(P_CN client_node, char *msg, int send_mode)
{

    // 保存头结点
    P_CN head_node;
    if (send_mode == SEND_MODE_BASE)
        head_node = client_node->server_inf_struct->online_client_head;

    if (send_mode == SEND_MODE_EXIT)
        head_node = client_node;

    char buffer[MSG_MAX_LEN];
    sprintf(buffer, "GROUP_C:%s", msg);

    // 遍历在线客户链表,实现发送广播消息
    for (P_CN tmp_client_node = head_node->next;
         tmp_client_node != head_node;
         tmp_client_node = tmp_client_node->next)
    {

        if (send_mode == SEND_MODE_BASE)
        { // 排除自身
            if (tmp_client_node->cli_fd != client_node->cli_fd)
            {
                if (write(tmp_client_node->cli_fd, buffer, strlen(buffer)) == -1)
                {
                    perror("write ...");
                    return false;
                }
            }
        }
        // 退出模式
        if (send_mode == SEND_MODE_EXIT)
        {

            if (write(tmp_client_node->cli_fd, EXIT_MASK, strlen(EXIT_MASK)) == -1)
            {
                perror("write ...");
                return false;
            }
        }
    }

    return true;
}

// 功能选择
bool Funtiction_Select(P_SBI server_inf_struct)
{
    char input[256];
    int choice;

    // 显示功能菜单
    while (1)
    {
        choice = 0;
        // system("clear");
        printf("\n————————————————————————————————————\n");
        printf("|             功能选择             |\n");
        printf("|          [1] 查看在线用户        |\n");
        printf("|          [2] 关闭服务器          |\n");
        printf("————————————————————————————————————\n");
        printf("请输入您的选择:");
        fflush(stdout); // 确保输出被立即刷新
        if (fgets(input, sizeof(input), stdin) == NULL)
        {
            perror("fgets failed");
            continue;
        }
        if (sscanf(input, "%d", &choice) == 1)
        {
            switch (choice)
            {
            case 1:
                Show_Online_Client(server_inf_struct);
                break;
            case 2:
                goto exit;
                break;
            default:
                printf("输入有误，请重新输入！\n");
                break;
            }
        }
        else
        {
            printf("输入有误，请重新输入！\n");
        }
    }
exit:
    TCP_Server_Destroy(server_inf_struct);

    return true;
}

// 显示在线用户
bool Show_Online_Client(P_SBI server_inf_struct)
{
    // 查看在线用户
    printf("\n————————————————————————————————————\n");
    printf("\n当前在线用户:\n");
    P_CN client_node = server_inf_struct->online_client_head->next;
    // 上锁
    pthread_mutex_lock(&(server_inf_struct->mutex));
    if (client_node == server_inf_struct->online_client_head)
    {
        printf("无在线用户!\n");
        pthread_mutex_unlock(&(server_inf_struct->mutex));
        return false;
    }

    while (client_node != server_inf_struct->online_client_head)
    {
        printf("%s\n", client_node->cli_ip);
        client_node = client_node->next;
    }
    // 解锁
    pthread_mutex_unlock(&(server_inf_struct->mutex));
    return true;
}


// 客户端消息应答函数
void *Mode_Select(void *arg)
{
    // 设置线程分离属性
    pthread_detach(pthread_self());

    P_CN client_node = (P_CN)arg;

    char msg[MSG_MAX_LEN];

    while (1)
    {
        memset(msg, 0, MSG_MAX_LEN);
        int read_ret = read(client_node->cli_fd, msg, MSG_MAX_LEN); // 读客户端的功能选择
        if (read_ret == -1)
        {
            perror("read error");
            pthread_exit((void *)-1);
        }
        else if (read_ret == 0) // 客户端断开连接
        {
            printf("\n%s掉线！\n", client_node->cli_ip);

            // 上锁
            pthread_mutex_lock(&(client_node->server_inf_struct->mutex));

            if (Del_Client_Node(client_node) == false)
            {
                printf("删除下线客户端结点失败！\n");
                // 解锁
                pthread_mutex_unlock(&(client_node->server_inf_struct->mutex));

                pthread_exit((void *)-1); // 线程退出
            }
            online_client_num--;
            // 解锁
            pthread_mutex_unlock(&(client_node->server_inf_struct->mutex));

            free(client_node); // 释放当前客户端结点堆空间
            break;
        }
        else // 处理客户端请求
        {
            if (strstr(PRIVATE_CHAT, msg) == 0 && strlen(msg) > 10) // 私聊
            {
                if (HandlePrivateChat(client_node->server_inf_struct, msg, client_node->cli_ip) == false)
                {
                    // 如果没有找到目标客户端，发送错误消息
                    char error_msg[256] = "PRIVATE_MSG:用户不在线或不存在";
                    if (write(client_node->cli_fd, error_msg, strlen(error_msg)) == -1)
                    {
                        perror("write error message");
                    }
                }
            }
            else if (strcmp(WE_CHAT, msg) == 0) // 群聊
            {
                printf("\n客户端：%s要群聊！\n", client_node->cli_ip);
                Broadcast_Task(client_node);
            }
            else if (strcmp(SHOW_WEATHER, msg) == 0) // 发送天气信息
            {
                char buffer[MSG_MAX_LEN];
                printf("\n客户端%s要显示天气\n", client_node->cli_ip);
                char *weather_info = get_weather();
                if (weather_info != (char *)-1)
                {
                    sprintf(buffer, "WEATHER:%s", weather_info);
                    write(client_node->cli_fd, buffer, strlen(buffer));
                    free(weather_info);
                    printf("发送天气信息成功！\n");
                }
                else
                {
                    weather_info == NULL;
                    printf("获取天气信息失败！\n");
                }
            }
            else if (strcmp(SHOW_ONLINE_CLI, msg) == 0) // 发送在线人员
            {
                printf("\n客户端%s要显示在线人员\n", client_node->cli_ip);
                Send_Onlie_Client(client_node->server_inf_struct, client_node);
            }
            else if (strcmp(TIME_MASK, msg) == 0) // 发送时间
            {
                char buffer[MSG_MAX_LEN];
                char *time_info = Get_Time();
                if (time_info)
                {
                    sprintf(buffer, "TIME:%s", time_info);
                    write(client_node->cli_fd, buffer, strlen(buffer));
                    free(time_info);
                }
                else
                {
                    printf("获取时间信息失败！\n");
                }
            }
            else if (strcmp(EXIT_MASK, msg) == 0) // 退出
            {
                continue;
            }
            else // 网络传输有误
            {
                printf("Error...Error...Error! %s\n", msg);
            }
            // // 使用线程池添加客户端连接任务
            // if (!Add_Task_Node(client_node->server_inf_struct->pthread_pool, msg, client_node))
            // {
            //     printf("向线程池添加任务失败！\n");
            //     close(client_node->cli_fd);
            //     pthread_exit((void *)-1);
            // }
            // Wake_Up_Pthread(client_node->server_inf_struct->pthread_pool);
        }
    }

    pthread_exit((void *)0);
}

// 将在线人数发送到客户端
bool Send_Onlie_Client(P_SBI server_inf_struct, P_CN client_node)
{
    // 初始化一个足够大的缓冲区来存储所有IP地址
    char ip_buffer[1024] = {0};
    int offset = 0;
    int first = 1; // 用于控制是否添加逗号分隔符

    // 上锁
    pthread_mutex_lock(&(server_inf_struct->mutex));
    if (server_inf_struct->online_client_head->next == server_inf_struct->online_client_head)
    {
        printf("无在线用户！\n");
        return false;
    }
    // 遍历在线客户端链表
    for (P_CN current = server_inf_struct->online_client_head->next;
         current != server_inf_struct->online_client_head;
         current = current->next)
    {
        // 跳过发送者
        if (current == client_node)
        {
            continue;
        }

        // 将当前客户端的IP地址添加到缓冲区
        if (first)
        {
            offset += snprintf(ip_buffer + offset, sizeof(ip_buffer) - offset, "IP_LIST:%s", current->cli_ip);
            first = 0; // 后续IP地址前添加逗号分隔符
        }
        else
        {
            offset += snprintf(ip_buffer + offset, sizeof(ip_buffer) - offset, ",%s", current->cli_ip);
        }
    }
    // 解锁
    pthread_mutex_unlock(&(server_inf_struct->mutex));
    // printf("在线用户列表：%s\n", ip_buffer);
    if (online_client_num > 1)
    {
        // 将IP地址列表发送给请求的客户端
        if (write(client_node->cli_fd, ip_buffer, strlen(ip_buffer)) == -1)
        {
            perror("write");
            return false;
        }
    }
    else // 只有一个在线用户
    {
        // printf("Onlie %d\n", online_client_num);
        const char *msg = "IP_LIST:No Other User Onlie";
        if (write(client_node->cli_fd, msg, strlen(msg) + 1) == -1)
        {
            perror("write");
            return false;
        }
    }

    printf("已发送在线用户列表！\n");

    return true;
}

// 处理私聊消息
bool HandlePrivateChat(P_SBI server_inf_struct, char *msg, char *sender_ip)
{
    char target_ip[IP_LEN];
    char private_msg[MSG_MAX_LEN];
    char full_msg[MSG_MAX_LEN + 12]; // 额外的空间用于 "PRIVATE_MSG:" 前缀

    // 解析消息，格式为 "P_Chat:目标IP:消息内容"
    sscanf(msg, "P_Chat:%15[^:]:%255s", target_ip, private_msg);

    // 查找目标客户端
    for (P_CN current = server_inf_struct->online_client_head->next;
         current != server_inf_struct->online_client_head;
         current = current->next)
    {
        if (strcmp(current->cli_ip, target_ip) == 0) // 找到目标客户端，发送私聊消息
        {
            int len = snprintf(full_msg, sizeof(full_msg), "PRIVATE_MSG:%s,发送: %s", sender_ip, private_msg);
            if (write(current->cli_fd, full_msg, len) == -1)
            {
                perror("write to target client");
            }
            printf("成功发送私聊消息！\n");
            return true;
        }
    }
    return false; // 没有找到目标客户端
}

// 获取当前时间
char *Get_Time()
{
    time_t now = time(NULL);
    struct tm *tm_now = localtime(&now);
    char *time_info = (char *)malloc(256);
    if (time_info == NULL)
    {
        perror("malloc");
        return NULL;
    }
    strftime(time_info, 256, "%Y-%m-%d %H:%M:%S", tm_now);
    return time_info;
}


// 销毁服务器
bool TCP_Server_Destroy(P_SBI server_inf_struct)
{

    // 关闭套接字
    if (shutdown(server_inf_struct->ser_fd, SHUT_RDWR) == -1)
    {
        perror("shutdown ...");
        return false;
    }

    // 广播给所有客户端要退出了
    Send_All_Client(server_inf_struct->online_client_head, EXIT_MASK, SEND_MODE_EXIT);
    // 等待每一个客户端退出
    while (1)
    {
        if (server_inf_struct->online_client_head->next == server_inf_struct->online_client_head)
        {
            free(server_inf_struct->online_client_head);
            break;
        }
        printf("等待客户端退出！\n");
        sleep(1);
    }
    // 等待线程结束
    pthread_join(server_inf_struct->wait_id, (void *)NULL);

    // 关闭套接字
    if (close(server_inf_struct->ser_fd) == -1)
    {
        perror("close ...");
        return false;
    }
    // 销毁互斥锁
    if (pthread_mutex_destroy(&(server_inf_struct->mutex)) != 0)
    {
        perror("pthread_mutex_destroy ...");
        return false;
    }

    // 销毁线程池
    if (Pthread_Pool_Free(server_inf_struct->pthread_pool) == false)
    {
        printf("线程池摧毁失败！\n");
        return -1;
    }
    printf("线程池资源已释放\n");

    // 释放广播结构体
    free(server_inf_struct);

    printf("资源已释放,服务器关闭！\n");
    return true;
}